//
//  AppPreferences.swift
//  Hermes
//
//  Created by FH on 2021/7/30.
//  Copyright © 2021 Agora. All rights reserved.
//

import Foundation

final class AppPreferences : PropsStatesContext, Deinitable {
    struct ScriptInfo : Codable {
        let inBundle: Bool
        let name: String
        let fileHash: String
        let type: ScriptBundleType
    }
    
    var dealloc = DeallocObserver()
    var isBinding: Bool {
        return self.$currScript.isBinding
    }
    @PropState
    var customScriptsLocation: String? = nil
    @PropState
    var scanAPIsLocation: String? = nil
    @PropState
    var scanParamsLocation: String? = nil
    @PropState
    var currScript: String = ""
    // key: path, value: (inBundle, scriptName, fileHash, type)
    @PropState
    var scriptInfos = [String : ScriptInfo]()
    // states for GridStreams VC
    @PropState
    var gridCount = 0
    @PropState
    var useAspectFill = false
    @PropState
    var notRemoveWhenOffline = false
    @PropState
    var layoutType: AppGridLayoutType = .Fixed
    @PropState
    var pageSize = 9
    @PropState
    var cellWidth: CGFloat = 0
    @PropState
    var cellHeight: CGFloat = 0
    @PropState
    var fullCellWidth: CGFloat = 0
    @PropState
    var fullCellHeight: CGFloat = 0
    // states for Logger VC
    @PropState
    var enableFilter = true
    @PropState
    var filterSelectors: Set<String> = [
        "rtcEngine:reportAudioVolumeIndicationOfSpeakers:totalVolume:",
        "rtcEngine:didApiCallExecute:api:result:",
        "rtcEngine:localVideoStateChange:error:",
        "rtcEngine:localVideoStats:",
        "rtcEngine:localAudioStateChange:error:",
        "rtcEngine:localAudioStats:",
        "rtcEngine:didAudioPublishStateChange:oldState:newState:elapseSinceLastState:",
        "rtcEngine:networkQuality:txQuality:rxQuality:",
        "rtcEngine:connectionChangedToState:reason:",
        "rtcEngine:reportRtcStats:",
        "rtcEngine:didOccurWarning:"
    ]
    
    var currScriptInfo: ScriptInfo? {
        for (_, info) in self.scriptInfos {
            if info.name == self.currScript {
                return info
            }
        }
        return nil
    }
    
    static func decode(_ encoder: [String : String]) -> [String : Any] {
        var preferences = [String : Any]()
        for (key, value) in encoder {
            if key == "scriptInfos", let json = value.data(using: .utf8) {
                let scriptInfos = try! JSONDecoder().decode([String : ScriptInfo].self, from: json)
                preferences[key] = scriptInfos
            } else if key == "filterSelectors", let json = value.data(using: .utf8) {
                let selectors = try! JSONDecoder().decode([String].self, from: json)
                preferences[key] = Set<String>(selectors)
            } else {
                let split = value.components(separatedBy: "^*^")
                preferences[key] = getAnyValue(by: split[0], and: split[1])
            }
        }
        return preferences
    }
    
    static func encode(_ preferences: [String : Any]) -> [String : String] {
        var local = [String : String]()
        for (key, value) in preferences {
            if key == "scriptInfos", let scriptInfos = preferences[key] as? [String : ScriptInfo] {
                let json = try! JSONEncoder().encode(scriptInfos)
                let jsonStr = String(data: json, encoding: .utf8)
                local[key] = jsonStr
            } else if key == "filterSelectors", let selectors = preferences[key] as? Set<String> {
                let json = try! JSONEncoder().encode(Array(selectors))
                let jsonStr = String(data: json, encoding: .utf8)
                local[key] = jsonStr
            } else {
                let (valueType, valueStr) = getAnyValueStr(from: value)
                local[key] = "\(valueType)^*^\(valueStr)"
            }
        }
        return local
    }
}
